﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Collections;
using System.Windows.Forms;

using Noris.Schedule.Support.Services;
using Noris.Schedule.Support.Data;
using Noris.Schedule.Support.Core;
using System.Data;
using Noris.Schedule.Support.Sql;
using Noris.Schedule.Support.DataFace;
using System.Threading;

namespace Noris.Schedule.Support
{
	#region CLASS AppConfigCls : registr konfigurace programu
	/// <summary>
	/// Konfigurace aplikace, data čtená z/do registru
	/// </summary>
	public class AppConfigCls : IDisposable
	{
		#region KONSTRUKCE
		/// <summary>
		/// Implicitní konstuktor
		/// </summary>
		public AppConfigCls()
		{
			// Poznámka: konstruktor této třídy NESMÍ NIKDY zavolat metody Stewarda, 
			// protože by došlo k nekonečnému zacyklení (Tvorba Stewarda => Tvorba AppConfig => Volání Stewarda => Založení Stewarda => a dokola)
			this._DbProfileList = new List<ConnectProfile>();
            this.UserData = new UserDataList();
			// Obecně: v konstruktoru nesmí být žádné další čtení dat. 
			// Až bude Steward plně připraven, zavolá naši metodu Init(), a tam můžeme zvesela číst data a pracovat se Stewardem.
		}
		/// <summary>
		/// Dispose
		/// </summary>
		public void Dispose()
		{
			this._ConfigWatchDispose();
		}
		#endregion
		#region INIT
		/// <summary>
		/// Iniciace dat AppConfigu, poté kdy je vytvořen, umístěn do Stewarda a Steward je připraven k práci.
		/// Volá se jen jedenkrát za život AppConfigu, a to vždy před jeho prvním použitím.
		/// </summary>
		internal void Init()
		{
		}
		#endregion
		#region DIRECTORIES
		/// <summary>
		/// Vrací cestu k lokálnímu adresáři, kde si aplikace může ukládat svoje data.
		/// Typicky je to adresář (System:Documents and Settings\All Users)\Data aplikací\NorisAps
		/// </summary>
		public string AppDataRootLocalPath
		{
			get
			{
				string dirName = System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "NorisAps");
				_CreateDirectoryIfNotExists(dirName);
				return dirName;
			}
		}
		/// <summary>
		/// Vrací cestu k lokálnímu adresáři, kde si aplikace může ukládat svoje data.
		/// Typicky je to adresář (System:Documents and Settings\All Users)\Data aplikací\NorisAps\IconCache
		/// </summary>
		public string AppDataIconCacheLocalPath
		{
			get
			{
				string dirName = System.IO.Path.Combine(AppDataRootLocalPath, "IconCache");
				_CreateDirectoryIfNotExists(dirName);
				return dirName;
			}
		}
		/// <summary>
		/// Zkontroluje existenci adresář (parametr), a pokud neexistuje pak jej vytvoří.
		/// </summary>
		/// <param name="dirName"></param>
		private static void _CreateDirectoryIfNotExists(string dirName)
		{
			if (!System.IO.Directory.Exists(dirName))
				System.IO.Directory.CreateDirectory(dirName);
		}
		#endregion
		#region PRIVÁTNÍ PROMĚNNÉ
		/// <summary>
		/// Aktuální platný connect profil
		/// </summary>
		private ConnectProfile _CurrentProfile;
		/// <summary>
		/// Seznam všech connect profilů, načtených z configu
		/// </summary>
		private List<ConnectProfile> _DbProfileList;
		#endregion
		#region ConnectInfo, last login
		/// <summary>
		/// Connect string do databáze
		/// </summary>
		public string ConnectString { get { return CurrentProfile.ProfileConnString; } set { CurrentProfile.ProfileConnString = value; } }
		/// <summary>
		/// Data aktuálního profilu
		/// </summary>
		public ConnectProfile CurrentProfile
		{
			get
			{
				if (this._CurrentProfile == null)
				{
					this._WinRegFindProfile();
				}
				return this._CurrentProfile;
			}
			set
			{
				if (value == null) return;

				this._CurrentProfile = value;
				this._WinRegSaveProfile();
			}
		}
		/// <summary>
		/// Metoda určí jméno Config souboru předaného v parametrech spuštění aplikace.
		/// </summary>
		private void _ConfigFileParamDetect()
		{
			this._ConfigFileParam = null;
			this._ConfigFileParamIsFilled = true;

			string paramConfig = Steward.ParamGet("C", true);
			if (!String.IsNullOrEmpty(paramConfig) && paramConfig.Length < 65)
			{
				// Pokud soubor nemá uvedenou cestu, doplníme cestu aplikace:
				//System.Windows.Forms.MessageBox.Show("paramConfig: délka = " + paramConfig.Length + " = " + paramConfig);
				//System.Windows.Forms.MessageBox.Show("ExecutablePath: délka = " + Application.ExecutablePath.Length + " = " + Application.ExecutablePath);

				if (System.IO.Path.GetDirectoryName(paramConfig) == String.Empty)
					paramConfig = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(Application.ExecutablePath), paramConfig);
				// Implicitní přípona:
				if (System.IO.Path.GetExtension(paramConfig) == String.Empty)
					paramConfig += ".config";
				// Pokud existuje, akceptujeme jej:
				if (System.IO.File.Exists(paramConfig))
					this._ConfigFileParam = paramConfig;
			}
		}
		/// <summary>
		/// Načte z WinReg info o posledním profilu, a pokusí se jej najít (nebo najde první).
		/// </summary>
		private void _WinRegFindProfile()
		{
			// 1. Načtu z WinReg:
            string profileName = Steward.WinRegReadString(_REGFOLDER, "CurrentProfileName", "");
            string profileData = Steward.WinRegReadString(_REGFOLDER, "CurrentProfileData", "");

			// 2. Najdu takový profil v seznamu:
			this._ConfigCheckLoad();
			ConnectProfile profile = null;
			if (this._DbProfileList.Count > 0)
			{
				if (!String.IsNullOrEmpty(profileName))
					profile = this._DbProfileList.Find(delegate(ConnectProfile p) { return (p.ProfileName == profileName); });
				if (profile == null && !String.IsNullOrEmpty(profileData))
					profile = this._DbProfileList.Find(delegate(ConnectProfile p) { return (p.SourceDatabase == profileData); });
				if (profile == null)
					profile = this._DbProfileList[0];
			}
			else
				profile = new ConnectProfile(0);

			// Nalezený nebo nový profil si zapamatujeme:
			this._CurrentProfile = profile;
		}
		/// <summary>
		/// Uloží do WinReg info o vybraném profilu
		/// </summary>
		private void _WinRegSaveProfile()
		{
            Steward.WinRegWriteString(_REGFOLDER, "CurrentProfileName", this._CurrentProfile.ProfileName);
            Steward.WinRegWriteString(_REGFOLDER, "CurrentProfileData", this._CurrentProfile.SourceDatabase);
		}
		/// <summary>
		/// Login, který naposledy uživatel použil pro přihlašování
		/// </summary>
		internal string LastLogin
		{
			get
			{
				if (this._LastLogin == null)
                    this._LastLogin = Steward.WinRegReadString(_REGFOLDER, "CurrentUserLogin", ""); ;
				return this._LastLogin;
			}
			set
			{
				this._LastLogin = value;
                Steward.WinRegWriteString(_REGFOLDER, "CurrentUserLogin", this._LastLogin);
			}
		}
		private string _LastLogin;
		#endregion
		#region NAČTENÍ DAT Z Schedule.config
		#region PUBLIC METODY A PROPERTY
		/// <summary>
		/// Soupis databázových profilů
		/// </summary>
		public List<ConnectProfile> DbProfileList
		{
			get
			{
				this._ConfigCheckLoad();
				return this._DbProfileList;
			}
		}
		/// <summary>
		/// Metoda najde a vrátí profil podle jeho jména.
		/// Pokud nenajde, vrátí null.
		/// </summary>
		/// <param name="profileName">Jméno hledaného profilu, exaktně</param>
		/// <returns></returns>
		public ConnectProfile DbProfileListFind(string profileName)
		{
			return this.DbProfileListFind(profileName, false);
		}
		/// <summary>
		/// Metoda najde a vrátí profil podle jeho jména.
		/// Pokud nenajde, vrátí null.
		/// </summary>
		/// <param name="profileName">Jméno hledaného profilu, exaktně nebo Case-Insensitive (podle parametru ignoreCase)</param>
		/// <param name="ignoreCase">true = hledá bez ohledu na velikost písmen / false (default) = exaktní shoda názvu</param>
		/// <returns></returns>
		public ConnectProfile DbProfileListFind(string profileName, bool ignoreCase)
		{
			StringComparison comparison = (ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
			return this.DbProfileList.Find(p => String.Equals(p.ProfileName, profileName, comparison));
		}
		/// <summary>
		/// Metoda přidá do seznamu profilů nový, s daným jménem, a rovnou jej vrátí.
		/// </summary>
		/// <param name="profileName">Jméno nového profilu. 
		/// Nesmí existovat v seznamu profilů, 
		/// což lze zjistit metodou this.DbProfileListFind(profileName, false).</param>
		/// <returns></returns>
		internal ConnectProfile DbProfileListAddNew(string profileName)
		{
			return this._DbProfileListAddNew(profileName, null);
		}
		/// <summary>
		/// Metoda přidá do seznamu profilů nový, s daným jménem, a rovnou jej vrátí.
		/// </summary>
		/// <param name="profileName">Jméno nového profilu. 
		/// Nesmí existovat v seznamu profilů, 
		/// což lze zjistit metodou this.DbProfileListFind(profileName, false).</param>
		/// <param name="connectString">Connect string. Může být null.</param>
		/// <returns></returns>
		internal ConnectProfile DbProfileListAddNew(string profileName, string connectString)
		{
			System.Data.SqlClient.SqlConnectionStringBuilder csb = new System.Data.SqlClient.SqlConnectionStringBuilder();
			if (!String.IsNullOrEmpty(connectString))
				csb = new System.Data.SqlClient.SqlConnectionStringBuilder(connectString);
			return this._DbProfileListAddNew(profileName, csb);
		}
		/// <summary>
		/// Metoda přidá do seznamu profilů nový, s daným jménem, a rovnou jej vrátí.
		/// </summary>
		/// <param name="profileName">Jméno nového profilu. 
		/// Nesmí existovat v seznamu profilů, 
		/// což lze zjistit metodou this.DbProfileListFind(profileName, false).</param>
		/// <param name="csb">String builder s daty</param>
		/// <returns></returns>
		internal ConnectProfile DbProfileListAddNew(string profileName, System.Data.SqlClient.SqlConnectionStringBuilder csb)
		{
			return this._DbProfileListAddNew(profileName, csb);
		}
		/// <summary>
		/// Metoda přidá do seznamu profilů nový, s daným jménem, a rovnou jej vrátí.
		/// </summary>
		/// <param name="profileName">Jméno nového profilu. 
		/// Nesmí existovat v seznamu profilů, 
		/// což lze zjistit metodou this.DbProfileListFind(profileName, false).</param>
		/// <param name="csb">String builder s daty. Nůže být null.</param>
		/// <returns></returns>
		private ConnectProfile _DbProfileListAddNew(string profileName, System.Data.SqlClient.SqlConnectionStringBuilder csb)
		{
			List<ConnectProfile> profileList = this.DbProfileList;       // Reference na živý seznam profilů, v případě potřeby se právě nyní načetl
			bool exists = profileList.Exists(p => String.Equals(p.ProfileName, profileName, StringComparison.Ordinal));
			if (exists)
				Throw.SysError(MessageInfo.Get("Chybné použití metody Steward.DbProfileListFind(), profil daného jména %0 již v seznamu existuje.", profileName));

			// Na vstupu může být csb = null. Pro takový případ použijeme empty objekt:
			System.Data.SqlClient.SqlConnectionStringBuilder cs = (csb != null ? csb : new System.Data.SqlClient.SqlConnectionStringBuilder());

			ConnectProfile connectProfile = new ConnectProfile(++this._ProfileLastID, profileName,
				cs.DataSource, cs.InitialCatalog, cs.UserID, cs.Password,
				false, cs.ConnectTimeout, cs.PersistSecurityInfo);
			profileList.Add(connectProfile);
			return connectProfile;
		}
		/// <summary>
		/// Metoda smaže položky ze seznamu profilů, kromě daného profilu.
		/// Metoda taky nesmaže aktuální profil (this.CurrentProfile).
		/// </summary>
		/// <param name="profileName">Jméno profilu, který se nebude mazat (exaktně)</param>
		/// <returns></returns>
		public void DbProfileListDeleteAllExcept(string profileName)
		{
			List<ConnectProfile> profileList = this.DbProfileList;       // Reference na živý seznam profilů, v případě potřeby se právě nyní načetl
			int currentId = this.CurrentProfile.ProfileID;
			for (int p = profileList.Count - 1; p >= 0; p--)
			{
				if (profileName != null && profileList[p].ProfileName == profileName) continue;
				if (profileList[p].ProfileID == currentId) continue;
				profileList.RemoveAt(p);
			}
		}
		/// <summary>
		/// Obsahuje plné jméno konfiguračního souboru (buď předané jako parametr, nebo defaultní)
		/// </summary>
		public string ConfigFile
		{
			get
			{
                if (!String.IsNullOrEmpty(this.ConfigFileExplicit)) return this.ConfigFileExplicit;
				if (!_ConfigFileParamIsFilled) this._ConfigFileParamDetect();
				if (_ConfigFileParam != null) return _ConfigFileParam;
				if (_ConfigFileDefault != null) return _ConfigFileDefault;
				_ConfigFileDefault = System.IO.Path.Combine(
					System.IO.Path.GetDirectoryName(Application.ExecutablePath),
					"Scheduler.cfg");
				return _ConfigFileDefault;
			}
		}
		/// <summary>
		/// Explicitně zadaný soubor Noris.config.
        /// Defaultně je null.
        /// Má přednost před všemi dalšími možnostmi zadání, typicky jej nastavuje aplikační kód.
		/// </summary>
        public string ConfigFileExplicit { get; set; }
		private int _ProfileLastID;
        /// <summary>
        /// Sklad, jehož pohyby se auditují
        /// </summary>
        public int DebugStock { get; set; }
        /// <summary>
        /// Plánovací jednotka, jejíž pohyby se auditují
        /// </summary>
        public int DebugPlanUnitS { get; set; }
        /// <summary>
        /// Vrací true, pokud se má debugovat daný údaj (PJ + sklad)
        /// </summary>
        /// <param name="planUnitS"></param>
        /// <param name="stock"></param>
        /// <returns></returns>
        public bool IsDebug(int planUnitS, int stock)
        {
            return (planUnitS == Steward.AppConfig.DebugPlanUnitS && stock == Steward.AppConfig.DebugStock);
        }
		#endregion
		#region PRIVATE PROMĚNNÉ a VÝKONNÉ METODY
		/// <summary>Příznak true, že aktuálně platný konfigurační soubor byl již načten</summary>
        private bool _ConfigIsLoaded
        {
            get
            {
                string configFile = this.ConfigFile;
                if (!String.Equals(configFile, this.__ConfigNameLoaded, StringComparison.InvariantCultureIgnoreCase))
                    return false;
                return this.__ConfigIsLoaded;
            }
        }
		/// <summary>Jméno konfiguračního souboru z parametrů aplikace </summary>
		private string _ConfigFileParam = null;
		/// <summary>Příznak true, že parametry spuštění aplikace byly prohledány za účelem nalezení jména konfiguračního souboru. Na true se nastaví při zavolání metody _ConfigFileParamDetect(), v ConfigFile_get()</summary>
		private bool _ConfigFileParamIsFilled = false;
		/// <summary>Defaultní jméno konfiguračního souboru = adresář aplikace a soubor "Scheduler.cfg"</summary>
		private string _ConfigFileDefault = null;
		/// <summary>Hlídací pes, který hlídá změnu konfiguračního souboru</summary>
		private System.IO.FileSystemWatcher _ConfigWatch;
		/// <summary>Velikost konfiguračního souboru, se kterou byl posledně načten</summary>
		private long _ConfigFileLength = -1;
		/// <summary>Datum a čas modifikace konfiguračního souboru, se kterou byl naposledy načten</summary>
		private DateTime _ConfigFileLastWrite = DateTime.MinValue;
		/// <summary>
		/// Zkontroluje, zda je načten konfigurační soubor, a pokud dosud načten není, tak zajistí jeho načtení.
		/// </summary>
		private void _ConfigCheckLoad()
		{
			if (_ConfigIsLoaded) return;
			_ConfigLoad();
		}
		/// <summary>
		/// Zajistí načtení konfiguračního souboru a zaháčkování FileWatch na něj
		/// </summary>
		private void _ConfigLoad()
		{
            // Info o tom, který config file jsme zpracovali:
            string configFile = this.ConfigFile;
            if (!__ConfigIsLoaded)
            {
                this.__ConfigIsLoaded = true;
            }
            this.__ConfigNameLoaded = configFile;
            this._ConfigFileLength = -1;
            this._ConfigFileLastWrite = DateTime.MinValue;

			// Init:
			this._DbProfileList = new List<ConnectProfile>();
            
            // Stop FileWatch:
            if (this._ConfigWatch != null)
            {
                this._ConfigWatch.EnableRaisingEvents = false;
                this._ConfigWatch.Dispose();
                this._ConfigWatch = null;
            }

			// Input file:
			if (String.IsNullOrEmpty(configFile)) return;
			System.IO.FileInfo fileInfo = new FileInfo(configFile);
			if (!fileInfo.Exists) return;
			this._ConfigFileLength = fileInfo.Length;
			this._ConfigFileLastWrite = fileInfo.LastWriteTimeUtc;
           
			// Load:
			this._ConfigLoadXml(configFile);

			// FileWatch:
			if (this._ConfigWatch == null)
			{
				this._ConfigWatch = new FileSystemWatcher();
				this._ConfigWatch.Path = fileInfo.DirectoryName;
				this._ConfigWatch.IncludeSubdirectories = false;
				this._ConfigWatch.Filter = fileInfo.Name;
				this._ConfigWatch.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size;
				this._ConfigWatch.Changed += new FileSystemEventHandler(this._ConfigWatch_Changed);
				this._ConfigWatch.EnableRaisingEvents = true;
			}
		}
        /// <summary>Fyzický příznak, že konfigurační soubor byl již načten</summary>
        private bool __ConfigIsLoaded = false;
        /// <summary>Jméno načteného konfiguračního souboru</summary>
        private string __ConfigNameLoaded = null;
        /// <summary>
		/// Fyzické načtení obsahu konfiguračního souboru do this
		/// </summary>
		/// <param name="configFile"></param>
		private void _ConfigLoadXml(string configFile)
		{
			//ConnectProfile profile = new ConnectProfile(++this._ProfileLastID, "Profil TEST",
			//    @"DAJ-7-D\DAJ_7_D", "norisVyvoj43_source", _USERNAME, "saruman", false, 1200, false);
			//this._DbProfileList.Add(profile);
			//return;

			System.Xml.XmlReaderSettings xmlSettings = new System.Xml.XmlReaderSettings();
			xmlSettings.CloseInput = true;
			xmlSettings.ConformanceLevel = System.Xml.ConformanceLevel.Document;
			xmlSettings.IgnoreComments = true;
			xmlSettings.IgnoreProcessingInstructions = true;
			xmlSettings.IgnoreWhitespace = true;
			xmlSettings.ProhibitDtd = true;
			xmlSettings.ValidationType = System.Xml.ValidationType.None;

			try
			{
				using (System.Xml.XmlReader xmlReader = System.Xml.XmlReader.Create(configFile, xmlSettings))
				{
					xmlReader.ReadStartElement();
					while (!xmlReader.EOF)
					{
						switch (xmlReader.Name.ToLower())
						{
							case "databases":
								this._ConfigLoadXmlDbList(xmlReader);
								break;
                            case "scheduler_debug":
                                this._ConfigLoadXmlDebug(xmlReader);
                                break;
							default:
								xmlReader.Skip();
								break;
						}
						xmlReader.Skip();              // Jde na další element v základní úrovni.
					}
				}
			}
			catch (Exception exc)
			{
				Noris.Schedule.Support.Core.Dialog.ShowError(exc, MessageInfo.Get("Načítání konfiguračního souboru %0.", configFile));
			}
		}
		/// <summary>
		/// Načte soupis databázových profilů
		/// </summary>
		/// <param name="xmlReader"></param>
		private void _ConfigLoadXmlDbList(System.Xml.XmlReader xmlReader)
		{
			xmlReader.ReadStartElement();      // Načte první element uvnitř sekce "databases"
			while (!xmlReader.EOF && xmlReader.NodeType == System.Xml.XmlNodeType.Element)
			{
				switch (xmlReader.Name.ToLower())
				{
					case "database":
						this._ConfigLoadXmlDbOne(xmlReader);
						break;
				}
				xmlReader.Skip();              // Jde na další element v rámci nadřazeného segmentu ("databases")
			}
		}
		/// <summary>
		/// Načte jeden db profil do interního pole
		/// </summary>
		/// <param name="xmlReader"></param>
		private void _ConfigLoadXmlDbOne(System.Xml.XmlReader xmlReader)
		{
			string dbProfileName = xmlReader.GetAttribute("Name");
			string dbDatabase = xmlReader.GetAttribute("Db");
			string dbServer = xmlReader.GetAttribute("Server");
			string dbPasswordCrypt = xmlReader.GetAttribute("Crypt");
			string dbPasswordAdmin = xmlReader.GetAttribute("AdmPass");
			string dbPasswordUser = xmlReader.GetAttribute("UsrPass");

			// Default values (viz Noris42\Srv\ConfigFile.cs, class ReadOnlyConfigFile, konstruktor):
			if (String.IsNullOrEmpty(dbDatabase))
				dbDatabase = "DB";
			if (String.IsNullOrEmpty(dbServer))
			{
				dbServer = "localhost";
				if (String.IsNullOrEmpty(dbProfileName))
					dbProfileName = dbDatabase;
			}
			if (String.IsNullOrEmpty(dbProfileName))
				dbProfileName = dbServer + "." + dbDatabase;

			// Is password crypted?
			bool isCrypt = !(dbPasswordCrypt != null && dbPasswordCrypt.ToLower().Trim() == "no");

			// Username - pokud je v atributu Crypt uvedeno "Win", pak se k SQL serveru připojíme přes Windows authentif., jinak přes uživatele "netadmin":
			bool isWinUser = (dbPasswordCrypt != null && dbPasswordCrypt.ToLower().Trim() == "win");
			string userId = (isWinUser ? null : _USERNAME);
			string password = dbPasswordAdmin;

			// ConnectProfile add to list:
			this._DbProfileList.Add(new ConnectProfile(++this._ProfileLastID, dbProfileName, dbServer, dbDatabase, userId, password, isCrypt, 1200, false));
		}
        /// <summary>
        /// Načte informace z elementu "scheduler_debug"
        /// </summary>
        /// <param name="xmlReader"></param>
        private void _ConfigLoadXmlDebug(System.Xml.XmlReader xmlReader)
        {
            this.DebugStock = _ConfigLoadAttributeInt(xmlReader, "stock");
            this.DebugPlanUnitS = _ConfigLoadAttributeInt(xmlReader, "plan_unit_s");
        }
        /// <summary>
        /// Vrátí Int32 z daného atributu XML
        /// </summary>
        /// <param name="xmlReader"></param>
        /// <param name="attributeName"></param>
        /// <returns></returns>
        private int _ConfigLoadAttributeInt(System.Xml.XmlReader xmlReader, string attributeName)
        {
            if (xmlReader == null) return 0;
            string value = xmlReader.GetAttribute(attributeName);
            if (String.IsNullOrEmpty(value)) return 0;
            int number;
            if (!Int32.TryParse(value, out number)) return 0;
            return number;
        }
        /// <summary>
		/// Po změně obsahu konfiguračního souboru
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void _ConfigWatch_Changed(object sender, FileSystemEventArgs e)
		{
			if (this._ConfigIsChanged())
			{
				this._ConfigLoad();
				MessageBox.Show("Changed !");
			}
		}
		/// <summary>
		/// Zjistí, zda konfigurační soubor je změněn od jeho posledního načtení
		/// </summary>
		/// <returns></returns>
		private bool _ConfigIsChanged()
		{
			string configFile = this.ConfigFile;
			if (String.IsNullOrEmpty(configFile)) return false;

			System.IO.FileInfo fi = new FileInfo(configFile);
			if (!fi.Exists) return false;
			return (this._ConfigFileLength != fi.Length || this._ConfigFileLastWrite != fi.LastWriteTimeUtc);
		}
		private void _ConfigWatchDispose()
		{
			if (_ConfigWatch != null)
				_ConfigWatch.Dispose();
			_ConfigWatch = null;
		}
		#endregion
		#endregion
		#region DALŠÍ PROPERTY
		/// <summary>
		/// Obrázek na pozadí okna Login
		/// </summary>
		public string LoginBackImage
		{
			get
			{
				if (!_LoginBackImageSearch)
				{
					_LoginBackImage = _LoginBackImageFind();
					_LoginBackImageSearch = true;
				}
				return _LoginBackImage;
			}
		}
		private string _LoginBackImage = null;
		private bool _LoginBackImageSearch = false;
		private string _LoginBackImageFind()
		{
			string file;
			file = System.IO.Path.Combine(Steward.ExecutablePath, @"pic\SchedulerSkin.png");
			if (System.IO.File.Exists(file)) return file;
			file = System.IO.Path.Combine(Steward.ExecutablePath, @"SchedulerSkin.png");
			if (System.IO.File.Exists(file)) return file;
			file = System.IO.Path.Combine(Steward.ExecutablePath, @"pic\SchedulerSkin.gif");
			if (System.IO.File.Exists(file)) return file;
			file = System.IO.Path.Combine(Steward.ExecutablePath, @"SchedulerSkin.gif");
			if (System.IO.File.Exists(file)) return file;
			file = System.IO.Path.Combine(Steward.ExecutablePath, @"pic\SchedulerSkin.jpg");
			if (System.IO.File.Exists(file)) return file;
			file = System.IO.Path.Combine(Steward.ExecutablePath, @"SchedulerSkin.jpg");
			if (System.IO.File.Exists(file)) return file;

			return null;
		}
        /// <summary>
        /// Úložiště libovolných dat
        /// </summary>
        public UserDataList UserData { get; set; }
        #endregion
        #region CONSTANTS
        /// <summary>
		/// Složka WinReg, kde se ukládají zdejší konfigurační data
		/// </summary>
		private const string _REGFOLDER = "Config";
		/// <summary>
		/// Uživatelské jméno pro připojení k SQL serveru, který se použije pro db profil z Noris.config
		/// </summary>
		private const string _USERNAME = "netadmin";
		#endregion
    }
	#endregion
}
